package unimelb.distSystems.project2;

/*
 * Lim Ching Lih, 308721
 * Yu Xia, 351025
 * Carlos Vasconcelos, 193554
 */

import java.awt.Container;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Font;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Arrays;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.ListIterator;

import javax.swing.BorderFactory;
import javax.swing.DefaultListModel;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JScrollBar;
import javax.swing.JScrollPane;
import javax.swing.JTextField;

import unimelb.distSystems.communications.CORBA.ServiceMessage;
import unimelb.distSystems.communications.CORBA.ServicePlayer;
import unimelb.distSystems.game.GameEngine;

import com.jme3.system.AppSettings;
import java.util.ArrayList;

/*
 * Subclass of GUIScreen where players are chatting and preparing to play
 */
public class MatchRoomScreen extends GUIScreen {
	/*
	 * GUI components
	 */
	private JButton leave_button = new JButton("Leave");
	private JButton ready_button = new JButton("I'm ready");
	private JButton start_button = new JButton("Start this racing");
	private JButton chat_button = new JButton("Send");
	private JButton selectcarleft_button = new JButton("< Previous car");
	private JButton selectcarright_button = new JButton("Next car >");
	private JLabel playerstatus_text = new JLabel();
	private JLabel chat_text = new JLabel("Room chat");
	private JTextField message_tf = new JTextField(15);
	private JLabel selectcar_text = new JLabel("");
	private JLabel track_text = new JLabel("");
	private JLabel title_text = new JLabel("");
	private JLabel player_text = new JLabel("Players in the match room");
	private ImagePanel trackpic_panel = new ImagePanel(null);
	private ImagePanel carpic_panel = new ImagePanel(null);
	private DefaultListModel message_list = new DefaultListModel();
	private JList chat_list = new JList(message_list);
	private DefaultListModel player_list = new DefaultListModel();
	private JList playerdisplay_list = new JList(player_list);
	private JScrollPane scroll_p = new JScrollPane(chat_list);
	
	//Variables
	private int current_car_index=0;
	private Game client=null;
	//private Thread monitor_thread=null;
	private MatchRoom cached_room=null;

	/*
	 * Constructor
	 */
	public MatchRoomScreen(Game client) {
		super();
		initialise_listeners(client);
		this.client=client;
		
		title_text.setFont(new Font(null,Font.BOLD,30));
		playerstatus_text.setFont(new Font(null,Font.BOLD,14));
		scroll_p.setWheelScrollingEnabled(true);
		scroll_p.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
	}

	/*
	 * @see unimelb.distSystems.project2.GUIScreen#perform_actions_prior_display()
	 */
	public void perform_actions_prior_display() {
		cached_room=client.get_current_matchroom();
		
		for(String[] info:Configurations.tracks)
		{
			if(Long.parseLong(info[0])==cached_room.getTrackID())
			{
				track_text.setText("Track: "+info[1]);
				trackpic_panel.load_new_image(info[2]);
			}
			
		}

		display_this_car(0);
		title_text.setText(cached_room.getMatchRoomName());

		start_button.setEnabled(false);
		if(cached_room.getHostID()==client.get_current_player().getPlayerID())
			start_button.setVisible(true);
		else
			start_button.setVisible(false);
		
		ready_button.setEnabled(true);
		selectcarleft_button.setEnabled(true);
		selectcarright_button.setEnabled(true);
		
		////////////////////////////////////
		//COBRA COMMUNICATION
		////////////////////////////////////
		//Get varying objects from the server
        String[] messages = client.getGameService().getChatMessages(cached_room.getMatchRoomID());
        ServicePlayer[] players = client.getGameService().getPlayers(cached_room.getMatchRoomID());
        
        display_messages(Arrays.asList(messages));
        display_players(Arrays.asList(players));
	}
	
	/*
	 * @see unimelb.distSystems.project2.GUIScreen#perform_actions_prior_exit()
	 */
	public void perform_actions_prior_exit()
	{
		//stop_monitor();
		
		////////////////////////////////////
		//COBRA COMMUNICATION
		////////////////////////////////////
		//Invoke leave(player_id) on server
		client.getGameService().leaveGame(cached_room.getMatchRoomID(), client.get_current_player().getPlayerID());
		client.cache_match_room(null);
	}

	/*
	 * @see unimelb.distSystems.project2.GUIScreen#display(java.awt.Container)
	 */
	public void display(Container screen_container) {
		GridBagConstraints c = new GridBagConstraints();
		c.fill = GridBagConstraints.HORIZONTAL;
		screen_container.setLayout(new GridBagLayout());
		
		JPanel title_p = new JPanel();
		title_p.setLayout(new GridBagLayout());
		title_p.add(title_text);
		c.gridx = 0;
		c.gridy = 0;
		screen_container.add(title_p,c);
		
		JPanel main_p = new JPanel();
		main_p.setLayout(new GridBagLayout());
		c.gridx = 0;
		c.gridy = 1;
		screen_container.add(main_p,c);
		
		JPanel left_column_p = new JPanel();
		left_column_p.setLayout(new GridBagLayout());
		c.gridx = 0;
		c.gridy = 0;
		main_p.add(left_column_p,c);
		
		c.gridx = 0;
		c.gridy = 0;
		left_column_p.add(chat_text,c);
		
		c.gridx = 0;
		c.gridy = 1;
		c.ipady=240;
		c.ipadx=350;
		left_column_p.add(scroll_p,c);
		c.ipady=1;
		c.ipadx=1;
		
		c.gridx = 0;
		c.gridy = 8;
		left_column_p.add(message_tf,c);
		
		c.gridx = 0;
		c.gridy = 9;
		left_column_p.add(chat_button,c);
		
		c.gridx = 0;
		c.gridy = 10;
		left_column_p.add(blank,c);
		
		c.gridx = 0;
		c.gridy = 11;
		left_column_p.add(player_text,c);
		
		c.gridx = 0;
		c.gridy = 12;
		c.ipady=120;
		c.ipadx=100;
		JScrollPane playerscroll_p = new JScrollPane(playerdisplay_list);
		left_column_p.add(playerscroll_p,c);
		c.ipady=1;
		c.ipadx=1;
		
		c.gridx = 0;
		c.gridy = 13;
		left_column_p.add(blank2,c);
		
		c.gridx = 0;
		c.gridy = 14;
		left_column_p.add(playerstatus_text,c);
		
		JPanel control_p = new JPanel();
		control_p.setLayout(new FlowLayout());
		control_p.add(ready_button);
		control_p.add(leave_button);
		control_p.add(start_button);
		c.gridx = 0;
		c.gridy = 15;
		left_column_p.add(control_p,c);
		
		JPanel right_column_p = new JPanel();
		right_column_p.setBorder(BorderFactory.createTitledBorder("Racing details"));
		right_column_p.setLayout(new GridBagLayout());
		c.gridx = 1;
		c.gridy = 0;
		c.insets=new Insets(0,20,0,0);
		main_p.add(right_column_p,c);
		
		c.insets=new Insets(0,10,0,0);
		c.gridx = 0;
		c.gridy = 0;
		right_column_p.add(track_text,c);
		
		c.gridx = 0;
		c.gridy = 1;
		c.ipadx=trackpic_panel.getImageWidth();
		c.ipady=trackpic_panel.getImageHeight();
		right_column_p.add(trackpic_panel,c);
		c.ipadx=1;
		c.ipady=1;
		
		c.gridx = 0;
		c.gridy = 2;
		right_column_p.add(selectcar_text,c);
		
		c.gridx = 0;
		c.gridy = 3;
		c.ipadx=carpic_panel.getImageWidth();
		c.ipady=carpic_panel.getImageHeight();
		right_column_p.add(carpic_panel,c);
		c.ipadx=1;
		c.ipady=1;
		
		JPanel carselection_p = new JPanel();
		carselection_p.setLayout(new FlowLayout());
		carselection_p.add(selectcarleft_button);
		carselection_p.add(selectcarright_button);
		c.gridx = 0;
		c.gridy = 4;
		right_column_p.add(carselection_p,c);
	}

	/*
	 * @see unimelb.distSystems.project2.GUIScreen#initialise_listeners(unimelb.distSystems.project2.Game)
	 */
	protected void initialise_listeners(final Game client) {
		/*
		 * Leave the match room
		 */
		leave_button.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent arg0) {			
				client.go_to_screen(Game.MENU_SCREEN);
			}
		});
		
		/*
		 * Add new message to chat log
		 */
		chat_button.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent arg0) {
				String message=message_tf.getText().trim();
				
				if(message.length()<=0)
					return;
				
				message_tf.setText("");
				
				////////////////////////////////////
				//COBRA COMMUNICATION
				////////////////////////////////////
				//Send the message to server with matchroom ID
                ServiceMessage sMessage = new ServiceMessage(client.get_current_player().getPlayerID(), client.get_current_player().getDriverName(), message);
                client.getGameService().sendChatMessage(client.get_current_matchroom().getMatchRoomID(), sMessage);
				
				////////////////////////////////////
				//COBRA COMMUNICATION
				////////////////////////////////////
				//Get all messages from server using matchroom ID
                //String[] messages = client.getGameService().getChatMessages(client.get_current_matchroom().getMatchRoomID());
				//display_messages(Arrays.asList(messages));
			}
		});
		
		/*
		 * Show previous car
		 */
		selectcarleft_button.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent arg0) {
				display_this_car(current_car_index-1);
			}
		});
		
		/*
		 * Show next car
		 */
		selectcarright_button.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent arg0) {
				display_this_car(current_car_index+1);
			}
		});
		
		/*
		 * FOR HOST PLAYER ONLY
		 * Host player can start the racing session when all players included himself/herself are ready
		 */
		start_button.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent arg0) {					
				////////////////////////////////////
				//COBRA COMMUNICATION
				////////////////////////////////////
				//1) Mark this room's isInRacingProgress flag true on server side
				//2) Signal to the server to create racing session with track & list of cars
				//After these, let the monitor thread to discover and launch the downloaded session
                client.getGameService().start(cached_room.getMatchRoomID());
			}
		});
		
		/*
		 * Let match room know he/she is ready
		 */
		ready_button.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent arg0) {
				ready_button.setEnabled(false);
				selectcarleft_button.setEnabled(false);
				selectcarright_button.setEnabled(false);
				
				////////////////////////////////////
				//COBRA COMMUNICATION
				////////////////////////////////////
				//Invoke the informReady(car_id) on the server based on matchroom ID and player ID
                client.getGameService().ready(cached_room.getMatchRoomID(), client.get_current_player().getPlayerID(), current_car_index);
			}
		});
	}
	
	/*
	 * Display selected car to player
	 * Input: int zero-start index of car list
	 * Output: Nothing
	 */
	private void display_this_car(int index)
	{
		if(index<0)
			index=Configurations.vehicles.length-1;
		else if(index >= Configurations.vehicles.length)
			index=0;
		
		String[] info = Configurations.vehicles[index];

		selectcar_text.setText("Your car: "+info[1]);
		carpic_panel.load_new_image(info[2]);
		current_car_index=index;
	}
	
	/*
	 * Load all chat messages into GUI chat components
	 * Input: List of messages
	 * Output: Nothing
	 */
	public void display_messages(List<String> messages)
	{
		message_list.removeAllElements();
		Iterator<String> itr = messages.iterator();
		
		while(itr.hasNext())
			message_list.addElement(itr.next());
		
		chat_list.setSelectedIndex(message_list.size()-1);
		scroll_p.validate();
		JScrollBar sb = scroll_p.getVerticalScrollBar();
		sb.setValue(sb.getMaximum());
	}
	
	/*
	 * Load all player details into GUI player list
	 * Input: List of players in the match room
	 * Output: Nothing
	 */
	public void display_players(List<ServicePlayer> players)
	{
        long host_id = cached_room.getHostID();
		player_list.removeAllElements();
		ListIterator<ServicePlayer> itr = players.listIterator();
        int ready = 0;
		
		while(itr.hasNext())
		{
			ServicePlayer player = itr.next();
			String driver_name=player.user.driverName;
			
			if(host_id==player.user.userID)
			{
				driver_name+=" [ Host ]";
				player_list.add(0,driver_name);
			}
			else
			{
				player_list.addElement(driver_name);
			}

            if(player.ready){
                ready++;
            }

            if(player.user.userID == client.get_current_player().getPlayerID()){
                if(!player.ready){
                    ready_button.setEnabled(true);
                }
            }
			
		}
		
        playerstatus_text.setText(ready+"/"+players.size()+" players are ready (Max "+cached_room.getMaxPlayers()+" players)");
        if(ready == players.size())
            start_button.setEnabled(true);
        else
            start_button.setEnabled(false);

	}
	
	/*
	 * Trigger new game frame (JMonkeyEngine3 frame)
	 * Input: Reference of RacingSession instance
	 * Output: Nothing
	 */
	public void launchRacingSession(ServicePlayer[] players)
	{
		RacingSession racing_session = new RacingSession(cached_room.getMatchRoomID(), getTrack(cached_room.getTrackID()), createCarList(Arrays.asList(players)));

		//Launch new frame of the game
		client.setGame(new GameEngine(client));
        try{
            client.getGame().launch(racing_session, client.get_current_player().getPlayerID());
        } catch(Exception e){}
	}

	
	/*
	 * INVALIDATED. COBRA now pings us not we
	 */
	/*
	 * Start pinging the server for latest copies of match room variables like chat messages
	 * Input: long value of unique ID of match room required when pinging the server
	 * Output: Nothing
	 * Expected: Active thread in background, pinging the server
	 */
	/*
	private void start_monitor()//<-- never used?
	{
		monitor_thread = new MatchRoomMonitor();
		monitor_thread.start();
	}
	*/
	
	/*
	 * Stop pinging the server
	 * Input: Nothing
	 * Output: Nothing
	 * Expected: The background monitor thread should be stopped
	 */
	/*
	private void stop_monitor()
	{
		if(monitor_thread==null)
			return;
		
		monitor_thread.stop();
	}
	*/
	
	/*
	 * Helper thread class
	 * Reason: Need background thread to regularly ping to the server for latest updates like new chat messages
	 */
	/*
	public class MatchRoomMonitor extends Thread
	{		
		/*
		 * Whole monitor flow
		 * @see java.lang.Thread#run()
		 */
		/*
		public void run() {
			while(true)
			{				
				////////////////////////////////////
				//COBRA COMMUNICATION
				////////////////////////////////////
				//Get latest copies of chat messages, player list,racing_session (or null), num of ready players
				String[] messages = client.getGameService().getChatMessages(cached_room.getMatchRoomID());
				ServicePlayer[] players = client.getGameService().getPlayers(cached_room.getMatchRoomID());
				
				//Update the GUI
				//display_messages(Arrays.asList(messages));
				//display_players(Arrays.asList(players),cached_room.getHostID());

				int numReadyPlayers=0;
				for(ServicePlayer this_player:players)
				{
					if(this_player.ready)
						numReadyPlayers++;
				}
				
				if(numReadyPlayers>=players.length)
					start_button.setEnabled(true);
				else
					start_button.setEnabled(false);
								
				////////////////////////////////////
				//COBRA COMMUNICATION
				////////////////////////////////////
				//Get the racing session from server side using host player ID or null if it didnt exist
				//RacingSession this_session=null;
				
				//if(this_session!=null)
					//launchRacingSession();
				
				try {
					Thread.sleep(Configurations.monitor_refresh_rate);
				} catch (InterruptedException e) {}
			}
		}
	}
	*/
	
	private Track getTrack(long track_id)
	{
		for(float[] track_info:Configurations.tracks_start_info)
		{
			if(track_info[0]==track_id)
			{
				Track this_track = new Track(track_id,
						track_info[1], track_info[2], track_info[3],
						track_info[4], track_info[5], track_info[6]);
				return this_track;
			}
		}
		
		System.out.println("WARNING: The track data ("+track_id+") cannot be found!");
		return null;
	}
	
	private LinkedList<Car> createCarList(List players)
	{
            LinkedList<Car> cars = new LinkedList();

            int index = 0;
            ListIterator li = players.listIterator();
            while(li.hasNext()){
                index = li.nextIndex() + 1;
                ServicePlayer player = (ServicePlayer)li.next();
                cars.add(new Car(index, player.user.userID, Configurations.vehicles[player.car][3]));
            }
				
            return cars;
	}
}
